<?php

namespace App\Service\Third;

use App\Constants\ErrorCode;
use Psr\EventDispatcher\EventDispatcherInterface;
use App\Event\HangupCallEvent;
use App\Helpers\RedisUtil;
use App\Model\CallbackLogAogra;
use App\Model\CallBase;
use App\Model\Message;
use App\Model\Service\ConsumeService;
use App\Model\VideoCall;
use App\Model\VoiceCall;
use App\Service\BaseService;

/**
 * 声网回调
 */
class AgoraCallbackService extends BaseService
{
    public function handle()
    {
        $callbackArray = $this->request->all();
        if (!in_array($callbackArray['eventType'], [107, 108, 103, 104])) return true;

        //签名验证
        $callbackString = json_encode($callbackArray);
        $key = env('AGORA_SECRET', '');
        $sid = bin2hex(hash_hmac("sha1", $callbackString, $key, true));
        $sign = $this->request->header('Agora-Signature');
        if (!check_dev_env() && $sid != $sign) {
            log_info(__CLASS__ . "==SignError=={$callbackString}");
            return $this->setError(ErrorCode::PARAMETER_ERROR, '签名错误~');
        }

        //解析参数
        $params = CallBase::getParams($callbackArray);

        //互斥锁
        $lockTime = 8;
        $params['eventType'] == 103 && $params['eventType'] = 107;
        $params['eventType'] == 104 && $params['eventType'] = 108;
        $key = "AgoraCallbackService_{$params['channelId']}_{$params['eventType']}_{$params['eventUid']}";
        if (RedisUtil::concurrentLock($key, $lockTime)) {
            return $this->setError(ErrorCode::SERVER_LOCK, '该事件已经处理，不重复处理~');
        }
        // log_info(__CLASS__ . "==concurrentLock==Key:{$key}");

        //请求日志
        CallbackLogAogra::addRecord(
            $params['channelId'],
            $params['eventType'],
            $params['eventUid'],
            $callbackString,
            $params['callType'],
        );
        log_info(__CLASS__ . "==agora=={$callbackString}");

        //处理不同事件回调
        switch ($params['eventType']) {
            case 107:
                //加入频道
                $this->answerCallback($params);
                break;
            case 108:
                //离开频道
                //$this->hangupCallback($params);
                break;
        }
        return ['result' => 1];
    }

    /**
     * 接听回调处理
     */
    function answerCallback($params = [])
    {
        $cls = $params['callType'] == 1 ? VideoCall::class : VoiceCall::class;
        return $cls::callbackChannelIn(
            $params['userId'],
            $params['chatUserId'],
            $params['channelId'],
            $params['eventUid']
        );
    }

    /**
     * 挂断回调处理
     */
    function hangupCallback($params = [])
    {
        $callCls = $params['callType'] == 1 ? VideoCall::class : VoiceCall::class;
        if ($params['callType'] == 1) {
            //视频通话
            $callRecord = VideoCall::checkRecordByChannelId($params['channelId']);
        } else {
            //语音通话
            $callRecord = VoiceCall::checkRecord($params['userId'], $params['chatUserId']);
            if ($callRecord && $callRecord->channel_id != $params['channelId']) {
                log_info(__CLASS__ . "==channelNotMatch==CallType:{$params['callType']}==Channel:{$params['channelId']}==LogId:{$callRecord->id}");
            }
        }
        //无记录
        if (!$callRecord) {
            log_info(__CLASS__ . "==noLogFind==CallType:{$params['callType']}==Channel:{$params['channelId']}");
            return;
        }
        //状态非通话状态
        if ($callRecord->status != CallBase::STATUS_ING) {
            log_info(__CLASS__ . "==noLogFind==CallType:{$params['callType']}==Channel:{$params['channelId']}");
            return;
        }

        //离开频道处理
        $callRecord = $callCls::channelOutUpdate($callRecord);
        //通话消费处理
        ConsumeService::settleCall($callRecord);
        //回调
        // Message::sendSlient([$params['userId'], $params['chatUserId']], 'CALL_OVER');
        //每日任务检测
        // make(EventDispatcherInterface::class)->dispatch(new HangupCallEvent($callRecord->user_id, $callRecord->chat_user_id, $callRecord->call_time));
        return;
    }
}
